#include <iostream>
#include <vector>
#include <fstream>
#include "portaudio.h"

using namespace std;

#define NUM_SECONDS       5
#define SAMPLE_RATE       16000
#define FRAMES_PER_BUFFER 512
#define NUM_CHANNELS      1
#define NUM_INPUT_DEVICE  5

typedef vector<short> VECTOR_SHORT;
typedef vector<short>::iterator VECTOR_SHORT_ITER;

VECTOR_SHORT m_vectorSamples;

static int recordCallback( const void *pInputBuffer, void *pOutputBuffer,
                           unsigned long iFramesPerBuffer,
                           const PaStreamCallbackTimeInfo* timeInfo,
                           PaStreamCallbackFlags statusFlags,
                           void *userData )
{
	short* pData = (short*) pInputBuffer;

    (void) pOutputBuffer; /* Prevent unused variable warnings. */
    (void) timeInfo;
    (void) statusFlags;
    (void) userData;

	if (pInputBuffer == NULL)
	{
		cout<<"Input buffer was NULL!"<<endl;
		return paContinue;
	}

	// Copy all the frames over to internal vector of samples
	for (unsigned long i = 0; i < iFramesPerBuffer; i++)
		m_vectorSamples.push_back(pData[i]);

	return paContinue;
}

void writeToFile(const string& strFilename)
{
	fstream fout(strFilename.c_str(), ios::out|ios::binary);

	short iSample;
	for(VECTOR_SHORT_ITER iter = m_vectorSamples.begin();iter != m_vectorSamples.end();iter++){
		iSample = (short) *iter;
		fout.write((char *) &iSample, sizeof(short));
	}

	fout.close();
}

int main(int argc, char const *argv[])
{
	/* code */
	PaError err = paNoError;

	m_vectorSamples.resize(sizeof(short)*512);

	err = Pa_Initialize();
	if(err != paNoError){
		cout<<"Portaudio Init Error:"<<Pa_GetErrorText(err)<<endl;
	}

	cout<<"*********Record Demo*********"<<endl;
	cout<<"*****************************"<<endl;

	PaStream*           stream;
	PaStreamParameters  inputParameters;

	inputParameters.device                    = NUM_INPUT_DEVICE;
	inputParameters.channelCount              = NUM_CHANNELS;
	inputParameters.sampleFormat              = paInt16;
	inputParameters.suggestedLatency          = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
	inputParameters.hostApiSpecificStreamInfo = NULL;

	err = Pa_OpenStream(
                &stream,
                &inputParameters,
                NULL,
                SAMPLE_RATE,
                FRAMES_PER_BUFFER,
                paClipOff,
                recordCallback,
                NULL);
	if(err != paNoError){
		cout<<"Portaudio OpenStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	cout<<"Press Enter to record"<<endl;
	char chWait;
	cin.get(chWait);

	err = Pa_StartStream(stream);
	if(err != paNoError){
		cout<<"Portaudio StartStream Error:"<<Pa_GetErrorText(err)<<endl;
	}


	cout<<"Recording ..."<<endl;	
	int delayCntr = 0;
    while(delayCntr++ < NUM_SECONDS)
    {
        Pa_Sleep(1000);
    }
    if(err < 0){
    	cout<<"Error"<<endl;
    }

	err = Pa_StopStream(stream); 
	if(err != paNoError){
		cout<<"Portaudio StopStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	cout<<"Writing samples to file"<<endl;
	writeToFile("recorded.raw");


	err = Pa_CloseStream(stream);
	if(err != paNoError){
		cout<<"Portaudio CloseStream Error:"<<Pa_GetErrorText(err)<<endl;
	}

	err = Pa_Terminate();
	if(err != paNoError){
		cout<<"Portaudio Terminate Error:"<<Pa_GetErrorText(err)<<endl;
	}


	return 0;
}
